package service

import (
	"context"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"monitoring-api/models"
	"monitoring-api/serializer"
	"time"
)

var Time [5]int64
var Interval [5]int64

type StatLogsInfoService struct {
	WebID   int64 `json:"web_id" form:"web_id"`
	Kind    int64 `json:"kind" form:"kind"`
	Time    int64 `json:"time" form:"time"`
	EndTime int64 `json:"end_time" form:"end_time"`
	Index   int64 `json:"index" form:"index"`
}

func (service *StatLogsInfoService) Stat() serializer.Response {
	Time = [5]int64{14400000, 86400000, 86400000 * 7, 86400000 * 14, 86400000 * 30}
	Interval = [5]int64{900000, 3600 * 2 * 1000, 86400000, 86400000, 86400000 * 2}
	var res [][]int64
	var err error
	if service.Kind == 0 {
		err, res = service.statErrors(Time[service.Time], Interval[service.Time])
		if err != nil {
			return serializer.Response{
				Code:    500,
				Message: "统计日志信息出错",
				Error:   err.Error(),
			}
		}
	} else if service.Kind == 1 {
		err, res = service.statPer(Time[service.Time], Interval[service.Time])
		if err != nil {
			return serializer.Response{
				Code:    500,
				Message: "统计日志信息出错",
				Error:   err.Error(),
			}
		}
	} else if service.Kind == 2 {
		if service.Index == 0 {
			err, res = service.statActions1(Time[service.Time], Interval[service.Time])
			if err != nil {
				return serializer.Response{
					Code:    500,
					Message: "统计日志信息出错",
					Error:   err.Error(),
				}
			}
		} else if service.Index == 1 {
			err, res = service.statActions2(Time[service.Time], Interval[service.Time])
			if err != nil {
				return serializer.Response{
					Code:    500,
					Message: "统计日志信息出错",
					Error:   err.Error(),
				}
			}
		}
	} else if service.Kind == 3 {
		if service.Index == 0 {
			err, res = service.statReqs1(Time[service.Time], Interval[service.Time])
			if err != nil {
				return serializer.Response{
					Code:    500,
					Message: "统计日志信息出错",
					Error:   err.Error(),
				}
			}
		} else if service.Index == 1 {
			err, res = service.statReqs2(Time[service.Time], Interval[service.Time])
			if err != nil {
				return serializer.Response{
					Code:    500,
					Message: "统计日志信息出错",
					Error:   err.Error(),
				}
			}
		}
	}
	return serializer.Response{
		Code:    0,
		Message: "统计日志信息成功",
		Data:    res,
	}
}

func (service *StatLogsInfoService) statErrors(Time int64, interval int64) (error, [][]int64) {
	var err error
	//初始化结果数组
	num := Time / interval
	res := make([][]int64, num)
	var i int64
	var index int64
	for i = 0; i < num; i++ {
		res[i] = make([]int64, 4)
	}
	statTime := time.Now().Unix()*1000 - Time
	endTime := statTime + interval
	for i = 0; i < num; i++ {
		for index = 0; index < 4; index++ {
			//查询语句
			filter := bson.D{{"webid", service.WebID},
				{"type", index},
				{"time", bson.D{{"$gt", statTime}}},
				{"time", bson.D{{"$lte", endTime}}},
			}
			count, err := models.Mongo.Collection("errors").CountDocuments(context.TODO(), filter)
			if err != nil {
				return err, [][]int64{}
			}
			res[i][index] = count
		}
		statTime = endTime
		endTime = endTime + interval
	}
	return err, res
}

//获取用户pv/uv
func (service *StatLogsInfoService) statActions1(Time int64, interval int64) (error, [][]int64) {
	num := Time / interval
	//初始化结果数组
	res := make([][]int64, num)
	var i int64
	for i = 0; i < num; i++ {
		res[i] = make([]int64, 2)
	}
	statTime := service.EndTime - Time
	endTime := statTime + interval
	// create the stage
	groupStage := bson.D{
		{"$group", bson.D{
			{"_id", "$user"},
			{"count", bson.D{
				{"$sum", 1},
			}},
		},
		}}
	for i = 0; i < num; i++ {
		match := bson.D{
			{"$match", bson.D{{"webid", service.WebID},
				{"time", bson.D{{"$gt", statTime}}},
				{"time", bson.D{{"$lte", endTime}}},
			}},
		}
		// pass the stage into a pipeline
		// pass the pipeline as the second paramter in the Aggregate() method
		cursor, err := models.Mongo.Collection("actions").Aggregate(context.TODO(), mongo.Pipeline{match, groupStage})
		if err != nil {
			return err, [][]int64{}
		}
		// display the results
		var results []bson.M
		if err = cursor.All(context.TODO(), &results); err != nil {
			if err != nil {
				return err, [][]int64{}
			}
		}
		for _, result := range results {
			Type := result["_id"].(int64)
			if Type == 0 {
				res[i][0] += int64(result["count"].(int32))
				res[i][1] += int64(result["count"].(int32))
			} else if Type == 1 {
				res[i][0] += int64(result["count"].(int32))
				res[i][1] += int64(result["count"].(int32))
			} else if Type == 2 {
				res[i][0] += int64(result["count"].(int32))
			}
		}
		statTime = endTime
		endTime = statTime + interval
	}
	return nil, res
}

//获取用户平均停留时间
func (service *StatLogsInfoService) statActions2(Time int64, interval int64) (error, [][]int64) {
	//初始化结果数组
	num := Time / interval
	res := make([][]int64, num)
	var i int64
	for i = 0; i < num; i++ {
		res[i] = make([]int64, 1)
	}
	statTime := service.EndTime - Time
	endTime := statTime + interval
	// create the stage
	groupStage := bson.D{
		{"$group", bson.D{
			{"_id", "null"},
			{"duration_avg", bson.D{
				{"$avg", "$duration"},
			}},
		},
		}}
	for i = 0; i < num; i++ {
		match := bson.D{
			{"$match", bson.D{{"webid", service.WebID},
				{"time", bson.D{{"$gt", statTime}}},
				{"time", bson.D{{"$lte", endTime}}},
			}},
		}
		// pass the stage into a pipeline
		// pass the pipeline as the second paramter in the Aggregate() method
		cursor, err := models.Mongo.Collection("actions").Aggregate(context.TODO(), mongo.Pipeline{match, groupStage})
		if err != nil {
			return err, [][]int64{}
		}
		// display the results
		var results []bson.M
		if err = cursor.All(context.TODO(), &results); err != nil {
			if err != nil {
				return err, [][]int64{}
			}
		}
		for _, result := range results {
			res[i][0] = int64(result["duration_avg"].(float64))
		}
		statTime = endTime
		endTime = statTime + interval
	}
	return nil, res
}

//获取请求的成功数和失败数
func (service *StatLogsInfoService) statReqs1(Time int64, interval int64) (error, [][]int64) {
	//初始化结果数组
	num := Time / interval
	//初始化结果数组
	res := make([][]int64, num)
	var i int64
	for i = 0; i < num; i++ {
		res[i] = make([]int64, 2)
	}
	statTime := service.EndTime - Time
	endTime := statTime + interval
	// create the stage
	groupStage := bson.D{
		{"$group", bson.D{
			{"_id", "$success"},
			{"count", bson.D{
				{"$sum", 1},
			}},
		},
		}}
	for i = 0; i < num; i++ {
		match := bson.D{
			{"$match", bson.D{{"webid", service.WebID},
				{"time", bson.D{{"$gt", statTime}}},
				{"time", bson.D{{"$lte", endTime}}},
			}},
		}
		// pass the stage into a pipeline
		// pass the pipeline as the second paramter in the Aggregate() method
		cursor, err := models.Mongo.Collection("requests").Aggregate(context.TODO(), mongo.Pipeline{match, groupStage})
		if err != nil {
			return err, [][]int64{}
		}
		// display the results
		var results []bson.M
		if err = cursor.All(context.TODO(), &results); err != nil {
			if err != nil {
				return err, [][]int64{}
			}
		}
		for _, result := range results {
			Type := result["_id"].(bool)
			if Type == true {
				res[i][0] += int64(result["count"].(int32))
			} else if Type == false {
				res[i][1] += int64(result["count"].(int32))
			}
		}
		statTime = endTime
		endTime = statTime + interval
	}
	return nil, res
}

//获取请求响应时间平均值
func (service *StatLogsInfoService) statReqs2(Time int64, interval int64) (error, [][]int64) {
	//初始化结果数组
	num := Time / interval
	//初始化结果数组
	res := make([][]int64, num)
	var i int64
	for i = 0; i < num; i++ {
		res[i] = make([]int64, 1)
	}
	statTime := service.EndTime - Time
	endTime := statTime + interval
	// create the stage
	groupStage := bson.D{
		{"$group", bson.D{
			{"_id", "null"},
			{"resTime_avg", bson.D{
				{"$avg", "$restime"},
			}},
		},
		}}
	for i = 0; i < num; i++ {
		match := bson.D{
			{"$match", bson.D{{"webid", service.WebID},
				{"time", bson.D{{"$gt", statTime}}},
				{"time", bson.D{{"$lte", endTime}}},
			}},
		}
		// pass the stage into a pipeline
		// pass the pipeline as the second paramter in the Aggregate() method
		cursor, err := models.Mongo.Collection("requests").Aggregate(context.TODO(), mongo.Pipeline{match, groupStage})
		if err != nil {
			return err, [][]int64{}
		}
		// display the results
		var results []bson.M
		if err = cursor.All(context.TODO(), &results); err != nil {
			if err != nil {
				return err, [][]int64{}
			}
		}
		for _, result := range results {
			res[i][0] = int64(result["resTime_avg"].(float64))
		}
		statTime = endTime
		endTime = statTime + interval
	}
	return nil, res
}

func (service *StatLogsInfoService) statPer(Time int64, interval int64) (error, [][]int64) {
	//初始化结果数组
	num := Time / interval
	res := make([][]int64, num)
	var i int64
	for i = 0; i < num; i++ {
		res[i] = make([]int64, 6)
	}
	statTime := service.EndTime - Time
	endTime := statTime + interval
	// create the stage
	groupStage := bson.D{
		{"$group", bson.D{
			{"_id", "null"},
			{"dcl_avg", bson.D{
				{"$avg", "$dcl"},
			}},
			{"fcp_avg", bson.D{
				{"$avg", "$fcp"},
			}},
			{"dns_avg", bson.D{
				{"$avg", "$dns"},
			}},
			{"fp_avg", bson.D{
				{"$avg", "$fp"},
			}},
			{"l_avg", bson.D{
				{"$avg", "$l"},
			}},
			{"lcp_avg", bson.D{
				{"$avg", "$lcp"},
			}},
		},
		}}
	for i = 0; i < num; i++ {
		match := bson.D{
			{"$match", bson.D{{"webid", service.WebID},
				{"time", bson.D{{"$gt", statTime}}},
				{"time", bson.D{{"$lte", endTime}}},
			}},
		}
		// pass the stage into a pipeline
		// pass the pipeline as the second paramter in the Aggregate() method
		cursor, err := models.Mongo.Collection("performances").Aggregate(context.TODO(), mongo.Pipeline{match, groupStage})
		if err != nil {
			return err, [][]int64{}
		}
		// display the results
		var results []bson.M
		if err = cursor.All(context.TODO(), &results); err != nil {
			if err != nil {
				return err, [][]int64{}
			}
		}
		for _, result := range results {
			res[i][0] = int64(result["dns_avg"].(float64))
			res[i][1] = int64(result["fp_avg"].(float64))
			res[i][2] = int64(result["fcp_avg"].(float64))
			res[i][3] = int64(result["lcp_avg"].(float64))
			res[i][4] = int64(result["dcl_avg"].(float64))
			res[i][5] = int64(result["l_avg"].(float64))
		}
		statTime = endTime
		endTime = statTime + interval
	}
	return nil, res
}
